module WeatherMan where

import Text.Regex.Posix

import Test.HUnit

digits :: String -> [Int]
digits record = map read $ (cleanedRecord record) =~ "[0-9]+"

cleanedRecord :: String -> String
cleanedRecord record = record =~ "^[ ]*[0-9]+[ ]+[0-9]+[ ]+[0-9]+"

dayOf :: String -> Maybe Int
dayOf record = maybeItem (digits record) 0

minTempOf :: String -> Maybe Int
minTempOf record = maybeItem (digits record) 2

maxTempOf :: String -> Maybe Int
maxTempOf record = maybeItem (digits record) 1

maybeItem :: [a] -> Int -> Maybe a
maybeItem list index =
    if (index < length list)
    then Just (list !! index)
    else Nothing
    
data Weather = 
    Weather {
        day     :: Int,
        minTemp :: Int,
        maxTemp :: Int
    }

tempSpread :: Weather -> Int
tempSpread weather = (maxTemp weather) - (minTemp weather)

instance Show Weather where
    show (Weather day minT maxT) = "Weather " ++ show (day, minT, maxT)
    
instance Eq Weather where
    Weather day1 min1 max1 == Weather day2 min2 max2 =
        (day1 == day2) &&
        (min1 == min2) &&
        (max1 == max2)
    
weatherOf :: String -> Maybe Weather
weatherOf record = case (dayOf record, minTempOf record, maxTempOf record) of {
    (Just day, Just minT, Just maxT) -> Just (Weather day minT maxT);
    _ -> Nothing
}

maybeItemTests = test [
        Nothing ~=? (maybeItem [1] 1),
        Just 1  ~=? (maybeItem [1] 0)
    ]

weatherTests = test [
        True                   ~=? (Weather 1 2 3) == (Weather 1 2 3),
        False                  ~=? (Weather 1 2 3) == (Weather 4 5 6),
        Nothing                ~=? weatherOf "I'm staying indoors",
        Just (Weather 1 10 20) ~=? weatherOf "1 20 10"
    ]
    
dayTests = test [
		Just 1 ~=? dayOf "1 40 20",
		Just 2 ~=? dayOf "2 39 21",
        Just 3 ~=? dayOf "   3  77    55    66          39.6       0.00         350  5.0 350   9  2.8  59 24 1016.8",
        Nothing ~=? dayOf "  Dy MxT   MnT   AvT "
	]

minTempTests = test [
		Just 20 ~=? minTempOf "1 40 20",
        Just 55 ~=? minTempOf "   3  77    55    66 "
	]

maxTempTests = test [
        Just 40 ~=? maxTempOf "1 40 20",
        Just 77 ~=? maxTempOf "   3  77    55    66 "
    ]

tempSpreadTests = test [
        10 ~=? tempSpread (Weather 1 15 25)
    ]

sort :: [a] -> (a -> a -> Bool) -> [a]
sort [] comparator = []
sort [x] comparator = [x]
sort (x:xs) comparator = insert (sort xs comparator)
    where insert [] = [x]
          insert (y:ys) | (comparator x y) = x : y : ys
                        | otherwise = y : insert ys
compareWith :: Ord b => (a -> b) -> (b -> b -> Bool) -> (a -> a -> Bool)
compareWith f op a b = f a `op` f b

tests = TestList [
    TestLabel "tempSpreadTests" tempSpreadTests,
    TestLabel "weatherTests" weatherTests,
    TestLabel "maybeItem" maybeItemTests,
	TestLabel "dayTests" dayTests,
	TestLabel "minTempTests" minTempTests,
	TestLabel "maxTempTests" maxTempTests
	]

main = do runTestTT tests
